﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 时间扩展类
    /// 所用时间戳的基准时间为1970-1-1 0:0:0.000,时间戳单位:毫秒
    /// </summary>
    public class TimeEx
    {
        private const DateTimeKind _DEFAULT = DateTimeKind.Local;
        private static ITimestampFactory _timestampFactory;
        /// <summary>
        /// 获取或设置时间戳工厂对象
        /// </summary>
        public static ITimestampFactory TimestampFactory
        {
            get { return _timestampFactory; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException(nameof(value));
                }

                _timestampFactory = value;
            }
        }


        static TimeEx()
        {
            _timestampFactory = new TicksTimestampFactory(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Local));
        }


        #region common

        /// <summary>
        /// 获取当前时间
        /// </summary>
        /// <param name="kind">时间类型</param>
        public static DateTime GetNow(DateTimeKind kind)
        {
            DateTime dateTime;
            switch (kind)
            {
                case DateTimeKind.Local:
                    dateTime = DateTime.Now;
                    break;
                case DateTimeKind.Utc:
                    dateTime = DateTime.UtcNow;
                    break;
                case DateTimeKind.Unspecified:
                    dateTime = TimeEx.ConvertDateTimeKind(DateTime.Now, DateTimeKind.Unspecified);
                    break;
                default:
                    throw new NotImplementedException(kind.ToString());
            }

            return dateTime;
        }

        /// <summary>
        /// 获取当前时间
        /// </summary>
        public static DateTime GetNow()
        {
            return GetNow(_timestampFactory.RefTime.Kind);
        }

        /// <summary>
        /// 转换DateTimeOffset为DateTime
        /// </summary>
        /// <param name="dateTime">DateTimeOffset</param>
        /// <param name="kind">目标时间类型</param>
        /// <returns>DateTime</returns>
        public static DateTime ConvertDateTimeOffsetToDateTime(DateTimeOffset dateTime, DateTimeKind kind)
        {
            DateTime time;
            switch (kind)
            {
                case DateTimeKind.Local:
                    time = dateTime.LocalDateTime;
                    break;
                case DateTimeKind.Utc:
                    time = dateTime.UtcDateTime;
                    break;
                case DateTimeKind.Unspecified:
                    time = dateTime.DateTime;
                    break;
                default:
                    throw new NotSupportedException(kind.ToString());
            }

            return time;
        }

        /// <summary>
        /// 将已知时间转换为另一种表示的时间
        /// </summary>
        /// <param name="time">已知时间</param>
        /// <param name="targetKind">目标时间类型</param>
        /// <returns>目标时间</returns>
        public static DateTime ConvertDateTimeKind(DateTime time, DateTimeKind targetKind)
        {
            if (time.Kind == targetKind)
            {
                return time;
            }

            switch (targetKind)
            {
                case DateTimeKind.Local:
                    time = time.ToLocalTime();
                    break;
                case DateTimeKind.Utc:
                    time = time.ToUniversalTime();
                    break;
                case DateTimeKind.Unspecified:
                    time = new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second, time.Millisecond, DateTimeKind.Unspecified);
                    break;
                default:
                    throw new NotSupportedException(targetKind.ToString());
            }

            return time;
        }

        /// <summary>
        /// 获取永久时间片
        /// </summary>
        /// <returns>永久时间片</returns>
        public static TimeSpan GetForeverTimeSpan()
        {
            //将1000年当作为永久时间
            return new TimeSpan(365 * 1000, 0, 0, 0, 0);
        }

        #endregion



        #region 基准时间1970-1-1 0:0:0.000时间戳
        /// <summary>
        /// 获取指定日期时间的时间戳
        /// </summary>
        /// <param name="dateTime">计算时间戳时间</param>
        /// <returns>当前时间的时间戳</returns>
        public static double GetTimestampD(DateTime dateTime)
        {
            return _timestampFactory.GetTimestamp(dateTime);
        }

        /// <summary>
        /// 获取指定日期时间的时间戳
        /// </summary>
        /// <param name="dateTime">计算时间戳时间</param>
        /// <returns>当前时间的时间戳</returns>
        public static long GetTimestamp(DateTime dateTime)
        {
            return Convert.ToInt64(GetTimestampD(dateTime));
        }




        /// <summary>
        /// 获取指定日期时间的时间戳
        /// </summary>
        /// <param name="dateTime">计算时间戳时间</param>
        /// <returns>当前时间的时间戳</returns>
        public static double GetTimestampD(DateTimeOffset dateTime)
        {
            DateTime time = ConvertDateTimeOffsetToDateTime(dateTime, _timestampFactory.RefTime.Kind);
            return _timestampFactory.GetTimestamp(time);
        }

        /// <summary>
        /// 获取指定日期时间的时间戳
        /// </summary>
        /// <param name="dateTime">计算时间戳时间</param>
        /// <returns>当前时间的时间戳</returns>
        public static long GetTimestamp(DateTimeOffset dateTime)
        {
            return Convert.ToInt64(GetTimestampD(dateTime));
        }

        /// <summary>
        /// 获取当前时间的时间戳
        /// </summary>
        /// <returns>当前时间的时间戳</returns>
        public static long GetTimestamp()
        {
            return _timestampFactory.GetTimestamp();
        }




        /// <summary>
        /// 时间戳转换为DateTime
        /// </summary>
        /// <param name="timestamp">时间戳</param>
        /// <param name="dateTimeKind">时间类型,默认类型为本地时间</param>
        /// <returns>时间</returns>
        public static DateTime TimestampToDateTime(long timestamp, DateTimeKind dateTimeKind = _DEFAULT)
        {
            DateTime dateTime = _timestampFactory.TimestampToDateTime(timestamp);

            if (dateTime.Kind != dateTimeKind)
            {
                dateTime = TimeEx.ConvertDateTimeKind(dateTime, dateTimeKind);
            }

            return dateTime;
        }

        /// <summary>
        /// 时间戳转换为DateTime
        /// </summary>
        /// <param name="timestamp">时间戳</param>
        /// <param name="dateTimeKind">时间类型,默认类型为本地时间</param>
        /// <returns>时间</returns>
        public static DateTime TimestampToDateTime(double timestamp, DateTimeKind dateTimeKind = _DEFAULT)
        {
            DateTime dateTime = _timestampFactory.TimestampToDateTime(timestamp);

            if (dateTime.Kind != dateTimeKind)
            {
                dateTime = TimeEx.ConvertDateTimeKind(dateTime, dateTimeKind);
            }

            return dateTime;
        }

        /// <summary>
        /// 时间戳转换为DateTimeOffset
        /// </summary>
        /// <param name="timestamp">时间戳</param>
        /// <param name="dateTimeKind">时间类型,默认类型为本地时间</param>
        /// <returns>时间</returns>
        public static DateTimeOffset TimestampToDateTimeOffset(long timestamp, DateTimeKind dateTimeKind = _DEFAULT)
        {
            DateTime dateTime = TimestampToDateTime(timestamp, dateTimeKind);
            return new DateTimeOffset(dateTime);
        }

        #endregion

    }
}
